unit Main;

{
  PasCalc
  Version 1.2 2011-05-26

  Copyright (C) 2011 KEEPER <yar.keeper@gmail.com>

  This file is part of the PasCalc Calculator

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See the file LICENSE.TXT, included in this distribution,
  for details about the copyright.

  This unit is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Dialogs,
  Menus, StdCtrls, ComCtrls, ExtCtrls, Windows, Help, Options, Analyser,
  ComplexOps, UsedTypes, History, Consts, Figure, Converter, CreateTable;

type

  { TfrmMain }

  TfrmMain = class(TForm)
    btn1: TButton;
    btn0: TButton;
    btnBr: TButton;
    btnExp: TButton;
    btnSpace: TButton;
    btnDot: TButton;
    btnPlus: TButton;
    btnMinus: TButton;
    btnMult: TButton;
    BtnDiv: TButton;
    btnI: TButton;
    btn2: TButton;
    btnStepLeft: TButton;
    btnBackSpace: TButton;
    btnStepRight: TButton;
    btnAnsw: TButton;
    btnPi: TButton;
    btnX: TButton;
    btn3: TButton;
    btn4: TButton;
    btn5: TButton;
    btn6: TButton;
    btn7: TButton;
    btn8: TButton;
    btn9: TButton;
    edExpr: TEdit;
    ilToolBar: TImageList;
    memResult: TMemo;
    smiAbs: TMenuItem;
    smiFact: TMenuItem;
    mi2EdField: TMenuItem;
    miCopy: TMenuItem;
    miCancel: TMenuItem;
    pmMemo: TPopupMenu;
    smiAbout: TMenuItem;
    smiHelp: TMenuItem;
    smiSettings: TMenuItem;
    smiHistory: TMenuItem;
    miOptions: TMenuItem;
    miHelp: TMenuItem;
    smiConsts: TMenuItem;
    rbDegrMode: TRadioButton;
    rbRadMode: TRadioButton;
    smiExpToAlg: TMenuItem;
    smiAlgToExp: TMenuItem;
    smiValConv: TMenuItem;
    smiComplConvert: TMenuItem;
    miConvert: TMenuItem;
    smiArcCos: TMenuItem;
    smiArcTg: TMenuItem;
    smiLn: TMenuItem;
    smiExp: TMenuItem;
    smiSqrN: TMenuItem;
    smiLogN: TMenuItem;
    smiSqrtN: TMenuItem;
    smiArcSin: TMenuItem;
    smiMore: TMenuItem;
    smiSqr: TMenuItem;
    smiSqrt: TMenuItem;
    smiCtg: TMenuItem;
    smiTg: TMenuItem;
    smiSin: TMenuItem;
    smiCos: TMenuItem;
    miFunctions: TMenuItem;
    mnuMain: TMainMenu;
    pcFunctions: TPageControl;
    pKeyboard: TTabSheet;
    pGraph: TTabSheet;
    tbMain: TToolBar;
    btnConv: TToolButton;
    sbtnConsts: TToolButton;
    btnHistory: TToolButton;
    btnHelp: TToolButton;
    pbtnSettings: TToolButton;
    BackSpaceTimer: TTimer;
    procedure BackSpaceTimerTimer(Sender: TObject);
    procedure btn1Click(Sender: TObject);
    procedure btnAnswClick(Sender: TObject);
    procedure btnBackSpaceMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure btnBackSpaceMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure btnBrClick(Sender: TObject);
    procedure btnHelpClick(Sender: TObject);
    procedure btnHistoryClick(Sender: TObject);
    procedure edExprKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure mi2EdFieldClick(Sender: TObject);
    procedure miCopyClick(Sender: TObject);
    procedure pbtnSettingsClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure pGraphShow(Sender: TObject);
    procedure sbtnConstsClick(Sender: TObject);
    procedure btnConvClick(Sender: TObject);
    procedure btnPiClick(Sender: TObject);
    procedure btnSpaceClick(Sender: TObject);
    procedure btnBackSpaceClick(Sender: TObject);
    procedure btnStepLeftClick(Sender: TObject);
    procedure btnStepRightClick(Sender: TObject);
    procedure MenuLangInit(Strs: TStringList);
    procedure FormLangInit(Strs: TStringList);
    procedure smiAboutClick(Sender: TObject);
    procedure smiAbsClick(Sender: TObject);
    procedure smiAlgToExpClick(Sender: TObject);
    procedure smiArcCosClick(Sender: TObject);
    procedure smiArcSinClick(Sender: TObject);
    procedure smiArcTgClick(Sender: TObject);
    procedure smiConstsClick(Sender: TObject);
    procedure smiCosClick(Sender: TObject);
    procedure smiCtgClick(Sender: TObject);
    procedure smiExpClick(Sender: TObject);
    procedure smiExpToAlgClick(Sender: TObject);
    procedure smiFactClick(Sender: TObject);
    procedure smiHelpClick(Sender: TObject);
    procedure smiHistoryClick(Sender: TObject);
    procedure smiLnClick(Sender: TObject);
    procedure smiLogNClick(Sender: TObject);
    procedure smiSettingsClick(Sender: TObject);
    procedure smiSinClick(Sender: TObject);
    procedure smiSqrClick(Sender: TObject);
    procedure smiSqrNClick(Sender: TObject);
    procedure smiSqrtClick(Sender: TObject);
    procedure smiSqrtNClick(Sender: TObject);
    procedure smiTgClick(Sender: TObject);
    procedure smiValConvClick(Sender: TObject);
  private
    fBackSpaceClicks: integer;
    procedure _SetFocus(Edit: TEdit; Pos: integer);
  public
    procedure StrIns(Edit: TEdit; const str: AnsiString;
      const IsBr: boolean = false);
    procedure RoundStr(Edit: TEdit; const ID: AnsiString);
    procedure LangInit(const LangFile: TFileName);
    procedure AddToLog(const s: AnsiString);
  end;
var
  frmMain: TfrmMain;

implementation

{ TfrmMain }

{$i consts.inc}

procedure TfrmMain.btn1Click(Sender: TObject);
var
  SelStart: integer;
begin
  SendMessage(edExpr.Handle, WM_CHAR,
    Ord((Sender as TButton).Caption[1]), 0);  //посылаем сообщение о нажатии на "железную" кнопку
  SelStart := edExpr.SelStart;
  edExpr.SetFocus;
  edExpr.SelStart := SelStart;
end;

procedure TfrmMain.BackSpaceTimerTimer(Sender: TObject);
begin
  BackSpaceTimer.Enabled := false;
  edExpr.Text := '';
  edExpr.SetFocus;
end;

procedure OutToMemo(Memo: TMemo; const str: ANSIString);
begin
  if Length(str) > MAX_STR_SIZE then Memo.Font.Height := MIN_FONT_SIZE else
    Memo.Font.Height := MAX_FONT_SIZE;
  Memo.Text := str;
end;

procedure TfrmMain.btnAnswClick(Sender: TObject);
var
  Answ: TComplex;
  Calc: TCalculator;
  ExpCompl: TExpComplex;
  History: TStringList;
begin
  if edExpr.Text = '' then
  begin
    OutToMemo(memResult, '0');
    exit;
  end;
  Calc := TCalculator.Create(edExpr.Text);
  try
    Calc.IsRad := rbRadMode.Checked;
    Calc.IsExp := fOptions.ComplPres = cpExp;
    Calc.IsLog := fOptions.IsLogging;
    Calc.LogFileName := SavePath + 'log.txt';
    Answ := Calc.CalcWithoutVars;
    if Calc.ErrorHappens then
    begin
      OutToMemo(memResult, Calc.GetLastError);
      exit;
    end;
    if fOptions.ComplPres = cpAlg then
      case fOptions.FloatPres of
        fpDefault: OutToMemo(memResult, ComplToStr(Answ));
        fpAuto: OutToMemo(memResult, ComplToStr(Answ, 6, 2));
        fpManual: OutToMemo(memResult, ComplToStr(Answ, fOptions.Size,
          fOptions.Fract));
      end else
      begin
        ExpCompl := Compl2ExpCompl(Answ);
        case fOptions.FloatPres of
          fpDefault: OutToMemo(memResult, ComplToStr(ExpCompl));
          fpAuto: OutToMemo(memResult, ComplToStr(ExpCompl, 6, 2));
          fpManual: OutToMemo(memResult, ComplToStr(ExpCompl, fOptions.Size,
            fOptions.Fract));
        end;
      end;
  finally
    Calc.Free;
    if fOptions.IsHistory then
    begin
      History := TStringList.Create;
      if FileExists(SavePath + 'history.txt') then History.LoadFromFile(SavePath + 'history.txt');
      History.Add(edExpr.Text + '=' + memResult.Text);
      History.SaveToFile(SavePath + 'history.txt');
      History.Free;
    end;
  end;
end;

procedure TfrmMain.btnBackSpaceMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  BackSpaceTimer.Enabled := true;
end;

procedure TfrmMain.btnBackSpaceMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  BackSpaceTimer.Enabled := false;
end;

procedure TfrmMain.btnBrClick(Sender: TObject);
begin
  RoundStr(edExpr, '()')
end;

procedure TfrmMain.btnHelpClick(Sender: TObject);
begin
  smiHelp.Click;
end;

procedure TfrmMain.btnHistoryClick(Sender: TObject);
begin
  smiHistory.Click;
end;

procedure TfrmMain.edExprKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_RETURN then btnAnsw.Click;
end;

procedure TfrmMain.mi2EdFieldClick(Sender: TObject);
begin
  StrIns(edExpr, memResult.Text);
end;

procedure TfrmMain.miCopyClick(Sender: TObject);
begin
  memResult.SelectAll;
  memResult.CopyToClipboard;
  memResult.SelLength := 0;
end;

procedure TfrmMain.pbtnSettingsClick(Sender: TObject);
begin
  smiSettings.Click;
end;

procedure TfrmMain.FormShow(Sender: TObject);
begin
  rbRadMode.Checked := fOptions.IsRad;
  LangInit(fOptions.Lang);
  edExpr.SetFocus;
end;

procedure TfrmMain.pGraphShow(Sender: TObject);
begin
  Figure.edExpr := frmMain.edExpr;
  frmGraph.Show;
  pcFunctions.ActivePageIndex := 0;
end;

procedure TfrmMain.sbtnConstsClick(Sender: TObject);
begin
  smiConsts.Click;
end;

procedure TfrmMain.btnConvClick(Sender: TObject);
begin
  smiValConv.Click;
end;

procedure TfrmMain.btnPiClick(Sender: TObject);
begin
  StrIns(edExpr, '3.141');
end;

procedure TfrmMain.btnSpaceClick(Sender: TObject);
begin
  StrIns(edExpr, ' ');
end;

procedure TfrmMain.btnBackSpaceClick(Sender: TObject);
var
  SelStart: integer;
begin
  SendMessage(edExpr.Handle, WM_CHAR, VK_Back, 0);
  SelStart := edExpr.SelStart;
  edExpr.SetFocus;
  edExpr.SelStart := SelStart;
end;

procedure TfrmMain.btnStepLeftClick(Sender: TObject);
var
  SelStart: integer;
begin
  SelStart := edExpr.SelStart;
  if SelStart = 0 then SelStart := 1;
  edExpr.SetFocus;
  edExpr.SelStart := SelStart - 1;
end;

procedure TfrmMain.btnStepRightClick(Sender: TObject);
var
  SelStart: integer;
begin
  SelStart := edExpr.SelStart;
  if SelStart = Length(edExpr.Text) then SelStart := Length(edExpr.Text) + 1;
  edExpr.SetFocus;
  edExpr.SelStart := SelStart + 1;
end;

procedure TfrmMain.MenuLangInit(Strs: TStringList);
begin
  miFunctions.Caption := Strs[1];
  smiMore.Caption := Strs[2];
  miConvert.Caption := Strs[3];
  smiComplConvert.Caption := Strs[4];
  smiAlgToExp.Caption := Strs[5];
  smiExpToAlg.Caption := Strs[6];
  smiValConv.Caption := Strs[7];
  miOptions.Caption := Strs[8];
  smiConsts.Caption := Strs[9];
  smiHistory.Caption := Strs[10];
  smiSettings.Caption := Strs[11];
  smiHelp.Caption := Strs[12];
  smiAbout.Caption := Strs[13];
  btnConv.Hint := Strs[84];
  sbtnConsts.Hint := Strs[85];
  pbtnSettings.Hint := Strs[86];
  btnHelp.Hint := Strs[87];
  btnHistory.Hint := Strs[88];
end;

procedure TfrmMain.FormLangInit(Strs: TStringList);
begin
  pKeyBoard.Caption := Strs[43];
  pGraph.Caption := Strs[44];
  rbDegrMode.Caption := Strs[45];
  rbRadMode.Caption := Strs[46];
end;

procedure TfrmMain.smiAboutClick(Sender: TObject);
begin
  ShowMessage(ABOUT_STR);
end;

procedure TfrmMain.smiAbsClick(Sender: TObject);
begin
  RoundStr(edExpr, 'abs()')
end;

procedure TfrmMain.smiAlgToExpClick(Sender: TObject);
var
  Calc: TCalculator;
  Compl: TComplex;
  ExpCompl: TExpComplex;
begin
  Calc := TCalculator.Create(edExpr.Text);
  try
    Calc.IsRad := false;
    Calc.IsExp := false;
    compl := Calc.CalcWithoutVars;
    if Calc.ErrorHappens then
    begin
      OutToMemo(memResult, Calc.GetLastError);
      exit;
    end;
  finally
    Calc.Free;
  end;
  ComplexOps.IsRad := false;
  ExpCompl := Compl2ExpCompl(compl);
  case fOptions.FloatPres of
    fpDefault: OutToMemo(memResult, ComplToStr(ExpCompl));
    fpAuto: OutToMemo(memResult, ComplToStr(ExpCompl, 6, 2));
    fpManual: OutToMemo(memResult, ComplToStr(ExpCompl, fOptions.Size,
      fOptions.Fract));
  end;
end;

procedure TfrmMain.smiArcCosClick(Sender: TObject);
begin
  RoundStr(edExpr, 'arccos()')
end;

procedure TfrmMain.smiArcSinClick(Sender: TObject);
begin
  RoundStr(edExpr, 'arcsin()')
end;

procedure TfrmMain.smiArcTgClick(Sender: TObject);
begin
  RoundStr(edExpr, 'arctg()')
end;

procedure TfrmMain.smiConstsClick(Sender: TObject);
begin
  frmConsts.Show;
  Consts.edExpr := edExpr;
end;

procedure TfrmMain.smiCosClick(Sender: TObject);
begin
  RoundStr(edExpr, 'cos()')
end;

procedure TfrmMain.smiCtgClick(Sender: TObject);
begin
  RoundStr(edExpr, 'ctg()');
end;

procedure TfrmMain.smiExpClick(Sender: TObject);
begin
  RoundStr(edExpr, 'exp()');
end;

procedure TfrmMain.smiExpToAlgClick(Sender: TObject);
var
  Calc: TCalculator;
begin
  Calc := TCalculator.Create(edExpr.Text);
  try
    Calc.IsRad := false;
    Calc.IsExp := true;
    case fOptions.FloatPres of
      fpDefault: OutToMemo(memResult, ComplToStr(Calc.CalcWithoutVars));
      fpAuto: OutToMemo(memResult, ComplToStr(Calc.CalcWithoutVars, 6, 2));
      fpManual: OutToMemo(memResult, ComplToStr(Calc.CalcWithoutVars, fOptions.Size,
        fOptions.Fract));
    end;
  finally
    Calc.Free;
  end;
end;

procedure TfrmMain.smiFactClick(Sender: TObject);
begin
  RoundStr(edExpr, 'fact()');
end;

procedure TfrmMain.smiHelpClick(Sender: TObject);
begin
  frmHelp.Show;
end;

procedure TfrmMain.smiHistoryClick(Sender: TObject);
begin
  frmHistory.Show;
  History.edExpr := frmMain.edExpr;
end;

procedure TfrmMain.smiLnClick(Sender: TObject);
begin
  RoundStr(edExpr, 'ln()');
end;

procedure TfrmMain.smiLogNClick(Sender: TObject);
begin
  RoundStr(edExpr, 'log( )');
  _SetFocus(edExpr, edExpr.SelStart-1);
end;

procedure TfrmMain.smiSettingsClick(Sender: TObject);
begin
  frmOptions.pcOptions.ActivePageIndex := 0;
  frmOptions.ShowModal;
  LangInit(fOptions.Lang);
end;

procedure TfrmMain.smiSinClick(Sender: TObject);
begin
  RoundStr(edExpr, 'sin()');
end;

procedure TfrmMain.smiSqrClick(Sender: TObject);
begin
  RoundStr(edExpr, 'sqr()')
end;

procedure TfrmMain.smiSqrNClick(Sender: TObject);
begin
  RoundStr(edExpr, 'pow( )');
  _SetFocus(edExpr, edExpr.SelStart-1);
end;

procedure TfrmMain.smiSqrtClick(Sender: TObject);
begin
  RoundStr(edExpr, 'sqrt()')
end;

procedure TfrmMain.smiSqrtNClick(Sender: TObject);
begin
  RoundStr(edExpr, 'SQRn( )');
  _SetFocus(edExpr, edExpr.SelStart-1);
end;

procedure TfrmMain.smiTgClick(Sender: TObject);
begin
  RoundStr(edExpr, 'tg()')
end;

procedure TfrmMain.smiValConvClick(Sender: TObject);
begin
  frmValConverrter.Show;
  Converter.edExpr := frmMain.edExpr;
end;

procedure TfrmMain._SetFocus(Edit: TEdit; Pos: integer);
begin
  Windows.SetFocus(Edit.Handle);
  Edit.SelStart := Pos;
end;

procedure TfrmMain.StrIns(Edit: TEdit; const str: AnsiString;
  const IsBr: boolean);
var
  CurPos: integer;
begin
  CurPos := Edit.SelStart;
  Edit.SelText := Str;
  if IsBr then _SetFocus(Edit, CurPos + Length(Str) - 1) else
     _SetFocus(Edit, CurPos + Length(Str));
end;

procedure TfrmMain.RoundStr(Edit: TEdit; const ID: AnsiString);
var
  Expr: AnsiString;
begin
  Expr := Edit.SelText;
  StrIns(Edit, ID, true);
  StrIns(Edit, Expr);
end;

procedure TfrmMain.LangInit(const LangFile: TFileName);
var
  Strings: TStringList;
  s: string;
begin
  if LangFile = '' then exit;
  if not FileExists(LangFile) then
  begin
    AddToLog('Lang file not found!');
    exit;
  end;
  Strings := TStringList.Create;
  Strings.LoadFromFile(LangFile);
  try
    MenuLangInit(Strings);
    FormLangInit(Strings);
    frmOptions.OptionsLangInit(Strings);
    frmHistory.LangInit(Strings);
    frmConsts.LangInit(Strings);
    frmGraph.LangInit(Strings);
    frmValConverrter.LangInit(Strings);
    frmCreateTable.LangInit(Strings);
  except
    AddToLog('Lang file corrupted!')
  end;
  Strings.Free;
end;

procedure TfrmMain.AddToLog(const s: AnsiString);
var
  Strs: TStringList;
begin
  if not fOptions.IsLogging then exit;
  Strs := TStringList.Create;
  if FileExists(SavePath + 'log.txt') then Strs.LoadFromFile(SavePath + 'log.txt');
  Strs.Add(DateToStr(Now) + ' ' + TimeToStr(Now));
  Strs.Add(s);
  Strs.SaveToFile(SavePath + 'log.txt');
  Strs.Free;
end;

initialization
  {$I Main.lrs}

end.

